// app.js
import Config from './utils/conf.js'
import Kits from './utils/kits.js'

const CryptoJS = require('crypto-js')

Date.prototype.addDays = function (days) {
    var date = new Date(this.valueOf())
    date.setDate(date.getDate() + days)
    return date
}
Date.prototype.addHours = function (hours) {
    var date = new Date(this.valueOf())
    date.setHours(date.getHours() + hours)
    return date
}
Date.prototype.format = function (fmt) {
    var o = {
        "M+": this.getMonth() + 1, //月份 
        "d+": this.getDate(), //日 
        "H+": this.getHours(), //小时 
        "m+": this.getMinutes(), //分 
        "s+": this.getSeconds(), //秒 
        "q+": Math.floor((this.getMonth() + 3) / 3), //季度 
        "S": this.getMilliseconds() //毫秒 
    }
    if (/(y+)/.test(fmt)) {
        fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length))
    }
    for (var k in o) {
        if (new RegExp("(" + k + ")").test(fmt)) {
            fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)))
        }
    }
    return fmt
}


require("./utils/ebus.js") // 导入事件总线，全局定义

App({
    Global: { // 全局数据
        Debug: Config.getConfig().Debug,
        Version: Config.getConfig().Version,
        AppId: Config.getConfig().AppId,
        FddAppId: Config.getConfig().FddAppId,
        Title: Config.getConfig().Title,
        QmapKey: Config.getConfig().QmapKey,
        API: Config.getConfig().API,
        OpenId: '',
        User: {},
        Token: 'Guest',
        Requests: new Set(), // 网络请求对象
        /*ColorUI 配置对象 */
        StatusBar: undefined,
        Custom: undefined,
        CustomBar: undefined
    },

    onLaunch() {
        // ColorUI 获取系统信息
        wx.getSystemInfo({
            success: e => {
                this.Global.StatusBar = e.statusBarHeight
                let capsule = wx.getMenuButtonBoundingClientRect()
                if (capsule) {
                    this.Global.Custom = capsule
                    this.Global.CustomBar = capsule.bottom + capsule.top - e.statusBarHeight
                } else {
                    this.Global.CustomBar = e.statusBarHeight + 50
                }
            }
        })
        // 执行登录
        this.doWxmnLogin(undefined)
        // 检测版本
        Kits.checkVersion()
    },
    onError(msg) {
        console.log(msg)
    },
    /* 自定义方法 */
    // 弹出提示
    doAlert(title, message, fnSucc) {
        wx.showModal({
            title: title,
            showCancel: false,
            content: message,
            confirmText: '知道了',
            success: () => {
                fnSucc && typeof fnSucc === 'function' && fnSucc()
            }
        })
    },
    // 进行小程序登录
    doWxmnLogin(callback) {
        if (this.login && callback == undefined) {
            return
        }
        this.login = true

        wx.setStorageSync('App.Uid', '')
        wx.setStorageSync('App.Token', 'Guest')
        wx.setStorageSync('App.Name', '')
        wx.setStorageSync('App.User', '{}')
        wx.setStorageSync('App.Users', '[]')

        wx.login({
            success: (res) => {
                this.login = false
                if (res.code) {
                    this.doPost({
                        uri: '/app/user/account/wxmn/signin',
                        body: {
                            appid: Config.getConfig().AppId,
                            code: res.code
                        },
                        fnSucc: resp => {
                            wx.setStorageSync('App.Users', JSON.stringify(resp.data.users))
                            if (wx.getStorageSync('App.Last.Uid') != '') {
                                let user = resp.data.users.find(u => u.id == wx.getStorageSync('App.Last.Uid'))
                                if (user != undefined) {
                                    wx.setStorageSync('App.Uid', user.id)
                                    wx.setStorageSync('App.Token', user.token)
                                    wx.setStorageSync('App.Name', user.name)
                                    wx.setStorageSync('App.User', JSON.stringify(user))
                                    this.Global.User = user
                                } else if (resp.data.users.length > 0) {
                                    wx.setStorageSync('App.Uid', resp.data.users[0].id)
                                    wx.setStorageSync('App.Token', resp.data.users[0].token)
                                    wx.setStorageSync('App.Name', resp.data.users[0].name)
                                    wx.setStorageSync('App.User', JSON.stringify(resp.data.users[0]))
                                    this.Global.User = resp.data.users[0]
                                }
                            } else if (resp.data.users.length > 0) {
                                wx.setStorageSync('App.Uid', resp.data.users[0].id)
                                wx.setStorageSync('App.Token', resp.data.users[0].token)
                                wx.setStorageSync('App.Name', resp.data.users[0].name)
                                wx.setStorageSync('App.User', JSON.stringify(resp.data.users[0]))
                                this.Global.User = resp.data.users[0]
                            }
                            this.Global.Token = this.Global.User.token
                            this.Global.OpenId = resp.data.openid
                            callback && callback.call()
                        },
                        fnFail: resp => {
                            wx.setStorageSync('App.Uid', '')
                            wx.setStorageSync('App.Token', 'Guest')
                            wx.setStorageSync('App.Name', '')
                            wx.setStorageSync('App.User', '{}')
                            wx.setStorageSync('App.Users', '[]')
                            this.Global.User = {}
                            this.Global.Token = 'Guest'
                            this.doAlert('出错啦', `获取用户信息失败，[${resp.stat.err}] ${resp.stat.msg}`)
                        }
                    })
                } else {
                    this.doAlert('微信服务异常', `小程序登录失败，请重新打开小程序`)
                }
            },
            fail: () => {
                this.login = false
                this.doAlert('微信服务异常', `小程序登录失败，请重新打开小程序`)
            },
        })
    },
    // Loading 
    doShowLoading(reqid) {
        this.Global.Requests.add(reqid)
        setTimeout(() => {
            if (this.Global.Requests.size > 0) {
                wx.showLoading({
                    mask: true,
                    title: 'loading...',
                })
            }
        }, 300)
    },
    doHideLoading(reqid) {
        if (reqid == 'All') {
            this.Global.Requests.clear()
        } else {
            this.Global.Requests.delete(reqid)
        }
        if (this.Global.Requests.size > 0) {
            return
        }
        wx.hideLoading()
    },
    // 执行网络请求，返回 RequestTask
    doPost({
        uri,
        body,
        noLoading,
        fnSucc,
        fnFail,
        fnComp
    }) {
        let url = this.Global.API + uri
        let bodyStr = JSON.stringify(body || {})
        
        // 调试：显示 Debug 状态
        console.log('Debug 状态:', this.Global.Debug)
        
        // 通用参数
        let token = wx.getStorageSync('App.Token') || 'Guest'
        let time = (new Date().getTime() / 1000).toFixed(0)
        let nonce = Kits.randomString()
        let version = '20000'
        let reqid = Kits.getUUID()

        // 加密Body数据（Debug 模式下不加密）
        if (!this.Global.Debug) {
            let key = CryptoJS.MD5(nonce + time).toString()
            let iv = CryptoJS.MD5(key).toString().substring(8, 24)
            let enx = CryptoJS.AES.encrypt(CryptoJS.enc.Utf8.parse(bodyStr), CryptoJS.enc.Utf8.parse(key), {
                iv: CryptoJS.enc.Utf8.parse(iv),
                mode: CryptoJS.mode.CBC,
                padding: CryptoJS.pad.Pkcs7,
            })
            bodyStr = CryptoJS.enc.Base64.stringify(enx.ciphertext)
        }

        // 计算签名
        let sign = CryptoJS.MD5(nonce + bodyStr + reqid).toString()

        // 封装url
        url = url + `?token=${token}&time=${time}&nonce=${nonce}&sign=${sign}&version=${version}&reqid=${reqid}&noaes=${this.Global.Debug ? 'true' : 'false'}`
        if (!noLoading) {
            this.doShowLoading(reqid)
        }
        return wx.request({
            url: url,
            method: 'POST',
            data: bodyStr,
            header: {
                'appid': this.Global.AppId
            },
            timeout: 5 * 60 * 1000,
            dataType: 'plain',
            success: (res) => {
                if (res.statusCode != 200) {
                    fnFail && typeof fnFail === 'function' ? fnFail({
                        stat: {
                            err: -1,
                            msg: `网络连接失败，代码：[${res.statusCode}]`
                        }
                    }) : this.doAlert('请求失败', `网络请求出现错误，请稍后重试。代码：[${res.statusCode}]`)

                    return
                }
                let plain = res.data
                let resp = {}
                if (plain.startsWith('{') && plain.endsWith('}')) {
                    resp = JSON.parse(plain)
                } else {
                    let key = CryptoJS.MD5(time + reqid).toString()
                    let iv = CryptoJS.MD5(key).toString().substring(8, 24)

                    let decrypt = CryptoJS.AES.decrypt(CryptoJS.enc.Base64.stringify(CryptoJS.enc.Base64.parse(plain)), CryptoJS.enc.Utf8.parse(key), {
                        iv: CryptoJS.enc.Utf8.parse(iv),
                        mode: CryptoJS.mode.CBC,
                        padding: CryptoJS.pad.Pkcs7,
                    })
                    resp = JSON.parse(decrypt.toString(CryptoJS.enc.Utf8))
                }
                console.log('Api -> ' + uri, (body || {}), resp)
                if (resp.stat.err == 0) {
                    fnSucc && typeof fnSucc === 'function' && fnSucc(resp)
                    return
                }
                if (resp.stat.err == 15) {
                    wx.setStorageSync('App.Uid', '')
                    wx.setStorageSync('App.Token', 'Guest')
                    wx.setStorageSync('App.Name', '')
                    wx.setStorageSync('App.User', '{}')
                    wx.setStorageSync('App.Users', '[]')
                    this.Global.User = {}
                    this.Global.OpenID = ''
                    wx.pub("ReloadUserInfo", {})
                    wx.pub("ReloadUserFin", {})

                    this.doAlert('登录已失效', `您的账号登录信息已过期，请重新登录`, () => {
                        this.doWxmnLogin(() => {
                            wx.reLaunch({
                                url: '/pages/splash/splash'
                            })
                        })
                    })


                    return
                }
                fnFail && typeof fnFail === 'function' ? fnFail(resp) : this.doAlert('请求失败', `[${resp.stat.err}] ${resp.stat.msg}`)
            },
            fail: () => {
                fnFail && typeof fnFail === 'function' ? fnFail({
                    stat: {
                        err: -1,
                        msg: '网络请求失败'
                    }
                }) : this.doAlert('请求失败', `您的网络连接好像出现了问题，请检查`)
            },
            complete: () => {
                if (!noLoading) {
                    this.doHideLoading(reqid)
                }
                fnComp && typeof fnComp === 'function' && fnComp()
            },
        })
    }
})